#include "daheng5000camera.h"

#include "../view/CameraViewWidget.h"
#include "../mainwindow.h"

Daheng5000Camera::Daheng5000Camera() {}

Daheng5000Camera::Daheng5000Camera(QWidget* pWidget,QString ip)
    :  m_pWidget(pWidget)
    , m_strIP(ip)
    , m_hDevice(NULL)
    , m_ui32DeviceNum(0)
    , m_strTriggerMode("On")
    , m_pBitmap(nullptr)
{
}

Daheng5000Camera::~Daheng5000Camera() {
    OnClose();
}

//掉线回调处理函数
static void GX_STDC OnDeviceOfflineCallbackFun(void* pUserParam)
{
    //收到掉线通知后，由用户主动发送通知主线程停止采集或者关闭设备等操作…
    //QMessageBox::warning(NULL,"警告","相机掉线！", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
    qDebug() << "相机掉线！";
    Daheng5000Camera* pCamera = (Daheng5000Camera*)pUserParam;
    if(pCamera != NULL){
        pCamera->SetSnap(FALSE);
        pCamera->SetOpen(FALSE);
        pCamera->ClearWidget();
    }
    return;
}

//图像回调处理函数
static void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{
    CameraViewWidget* pCameraViewWidget =  (CameraViewWidget*)pFrame->pUserParam;
    if (pFrame->status == GX_FRAME_STATUS_SUCCESS)
    {
        //对图像进行某些操作
        pCameraViewWidget->m_viewBox->SetImage(pFrame);
    }

    return;
}

QString Daheng5000Camera::GetIP(){
    return m_strIP;
}

int Daheng5000Camera::OpenDevice()
{
    uint32_t nDSNum;
    stOpenParam.accessMode  = GX_ACCESS_EXCLUSIVE;
    stOpenParam.openMode    = GX_OPEN_IP;
    QByteArray ba           = m_strIP.toLatin1();
    stOpenParam.pszContent  = ba.data();

    // 如果设备已经打开则关闭，保证相机在初始化出错情况能再次打开
    if(m_hDevice != NULL){
        emStatus = GXCloseDevice(m_hDevice);
        m_hDevice = NULL;
    }
    // 打开设备
    // -5 无效参数,一般是指针为NULL或输入的IP等参数格式无效
    emStatus = GXOpenDevice(&stOpenParam,&m_hDevice);
    if(emStatus != GX_STATUS_SUCCESS){
        qDebug() << QString("打开相机失败：%1!").arg(emStatus);
        return emStatus;
    }

    SetOpen(TRUE);

    // 获取流通道数
    emStatus = GXGetDataStreamNumFromDev(m_hDevice,&nDSNum);
    if(nDSNum > 0){
        emStatus = GXGetDataStreamHandleFromDev(m_hDevice,1,&m_hStream);
    }

    // 建议用户在打开网络相机之后，根据当前网络环境设置相机的流通道包长值
    // 以提高网络相机的采集性能，设置方法如下
    {
        bool bImplementPackSize = false;
        uint32_t unPacketSize = 0;

        // 判断设备是否支持流通道数据包功能
        GX_NODE_ACCESS_MODE emAccessMode = GX_NODE_ACCESS_MODE_NI;
        emStatus = GXGetNodeAccessMode(m_hDevice,"GevSCPSPacketSize",&emAccessMode);

        if((emAccessMode != GX_NODE_ACCESS_MODE_NI)
            && (emAccessMode != GX_NODE_ACCESS_MODE_UNDEF)
            && (emAccessMode != GX_NODE_ACCESS_MODE_NA)){
            bImplementPackSize = true;
        }

        if(bImplementPackSize){
            emStatus = GXGetOptimalPacketSize(m_hDevice,&unPacketSize);

            emStatus = GXSetIntValue(m_hDevice,"GevSCPSPacketSize",unPacketSize);
        }
    }

    do{
        m_hWidgetCamera = (HWND)m_pWidget->winId();
        m_pBitmap = new CGXBitmap(m_hDevice,m_hWidgetCamera);
    }while(false);

    return emStatus;
}

int Daheng5000Camera::InitDevice(QString triggerMode){
    GX_STATUS emStatus = GX_STATUS_SUCCESS;
    m_strTriggerMode = triggerMode;

    //设置触发模式为 ON
    emStatus = GXSetEnumValueByString(m_hDevice, "TriggerMode", triggerMode.toLatin1());
    // 设置采集模式连续采集
    emStatus = GXSetEnumValueByString(m_hDevice,"AcquisitionMode","Continuous");

    return emStatus;
}

int Daheng5000Camera::ConfigCaptureVideo()
{
    // 为图像显示准备资源
    emStatus = m_pBitmap->PrepareForShowImg();
    if(emStatus != GX_STATUS_SUCCESS){
        return emStatus;
    }
    // 注册图像采集回调函数
    emStatus = GXRegisterCaptureCallback(m_hDevice,m_pWidget,OnFrameCallbackFun);
    if(emStatus != GX_STATUS_SUCCESS){
        //QMessageBox::warning(NULL,"警告","注册图像采集回调函数！", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        qDebug() << "注册图像采集回调函数！";
        return emStatus;
    }

    //注册设备掉线回调函数
    /*emStatus = GXRegisterDeviceOfflineCallback(m_hDevice,this,
                                               OnDeviceOfflineCallbackFun,
                                               &m_hDevcieOfflineCallBack);
    if(emStatus != GX_STATUS_SUCCESS){
        //QMessageBox::warning(NULL,"警告","注册设备掉线回调函数失败！", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        qDebug() << "注册设备掉线回调函数失败！";
        return emStatus;
    }*/
    //---------------------
    //
    //事件通知会通过 OnDeviceOfflineCallbackFun 接口返给用户
    //
    //---------------------

    /*
    // 设置流层Buffer处理模式
    emStatus = GXSetEnumValueByString(m_hStream,"StreamBufferHandlingMode","OldestFirst");
    // 设置流层Buffer处理模式
    //emStatus = GXSetEnumValueByString(m_hStream,"StreamBufferHandlingMode","NewestOnly");
    if(emStatus != GX_STATUS_SUCCESS){
        //QMessageBox::warning(NULL,"警告","设置流层Buffer处理模式失败！", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        qDebug() << "设置流层Buffer处理模式失败！";
        return emStatus;
    }
    */
    return emStatus;
}

int Daheng5000Camera::UnconfigCaptureVideo()
{
    // 为图像显示准备资源
    if(m_pBitmap != nullptr){
        m_pBitmap->UnPrepareForShowImg();
    }

    // 注册图像采集回调函数
    emStatus = GXUnregisterCaptureCallback(m_hDevice);
    if(emStatus != GX_STATUS_SUCCESS){
        qDebug() << "取消注册图像采集回调函数！";
        return emStatus;
    }

    return emStatus;
}

int Daheng5000Camera::StartSnap(){
    // 发开始采集命令
    emStatus = GXSetCommandValue(m_hDevice,"AcquisitionStart");
    if(emStatus != GX_STATUS_SUCCESS){
        //QMessageBox::warning(NULL,"警告","相机打开失败！", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
        qDebug() << "开始相机采集失败!";
        return emStatus;
    }

    this->SetSnap(TRUE);
    return emStatus;
}

/**
 * @brief DahengCamera::TriggerSoftware
 * @return 软触发，是为了采集一张图片
 */

int Daheng5000Camera::TriggerSoftware(){
    //设置触发模式为 ON
    if(m_strTriggerMode == "Off"){
        InitDevice("On");
    }
    StartSnap();
    emStatus = GXSetCommandValue(m_hDevice, "TriggerSoftware");
    return 0;
}
/**
 * @brief DahengCamera::CaptureVideo
 * @return 采集连续的视频，为了调试使用
 */
int Daheng5000Camera::CaptureVideo(){
    if(m_strTriggerMode == "On"){
        InitDevice("Off");
    }
    StartSnap();
    return 0;
}

int Daheng5000Camera::ClearWidget(){
    m_pWidget->setStyleSheet("QWidget { background-color: #FF0000; }");
    return 0;
}

int Daheng5000Camera::StopSnap()
{
    emStatus = GXSetCommandValue(m_hDevice,"AcquisitionStop");
    if(emStatus != GX_STATUS_SUCCESS){
        qDebug()<<"停止相机采集失败!";
    }

    //GX_STATUS emStatus = GXFlushQueue(m_hDevice);

    emStatus = GXSetCommandValue(m_hDevice,"AcquisitionStart");
    GX_STATUS emErrCode = GX_STATUS_SUCCESS;
    char* pszTemp = NULL;
    size_t nSize = 0;
    //传入 NULL 指针，获取实际长度，然后申请 buffer 再获取描述信息
    GXGetLastError(&emErrCode, NULL, &nSize);
    pszTemp = new char[nSize];
    emStatus = GXGetLastError(&emErrCode, pszTemp, &nSize);
    qDebug() << pszTemp;

    if(emStatus != GX_STATUS_SUCCESS){
        qDebug()<<"开始相机采集失败!";
    }

    //注销设备掉线事件回调
    //emStatus = GXUnregisterDeviceOfflineCallback(m_hDevice,m_hDevcieOfflineCallBack);

    emStatus = GXUnregisterCaptureCallback(m_hDevice);
    if(emStatus != GX_STATUS_SUCCESS){
        qDebug()<<"UnregisterCaptureCallback failed!";
    }

    return emStatus;
}


int Daheng5000Camera::CloseDevice()
{
    SetOpen(FALSE);

    if(m_pBitmap == nullptr){
        free(m_pBitmap);
        m_pBitmap = nullptr;
    }

    emStatus = GXCloseDevice(m_hDevice);
    if(emStatus != GX_STATUS_SUCCESS){
        qDebug()<<"CloseCamera failed!";
    }
    return emStatus;
}

int Daheng5000Camera::OnClose(){
    GX_STATUS emStatus = GX_STATUS_SUCCESS;

    // 若未停采则先停止采集
    if(this->IsSnap()){
        // 发送停止采集命令
        emStatus = GXSetCommandValue(m_hDevice,"AcquisitionStop");

        // 注销回调
        emStatus = GXUnregisterCaptureCallback(m_hDevice);
        this->SetSnap(FALSE);
    }

    //未关闭设备则关闭设备
    if(this->IsOpen()){
        emStatus = GXCloseDevice(m_hDevice);
        this->SetOpen(FALSE);
        m_hDevice = NULL;
    }

    return emStatus;
}

int Daheng5000Camera::CaptureImage(){
    int imageNum = 0;
    GX_FRAME_DATA       m_stFrameData;

    qDebug() << "content = " << imageNum;

    int m_nEditTimeOut = 500;
    //每次发送触发命令之前清空采集输出队列
    //防止库内部缓存帧，造成本次GXGetImage得到的图像是上次发送触发得到的图
    GX_STATUS emStatus = GXFlushQueue(m_hDevice);

    emStatus = GXSetCommandValue(m_hDevice, "AcquisitionStart");
    //发送软触发命令
    emStatus = GXSetCommandValue(m_hDevice,"TriggerSoftware");

    //获取图像
    emStatus = GXGetImage(m_hDevice, &m_stFrameData, m_nEditTimeOut);
    int nWidth = m_stFrameData.nWidth;
    int nHeight = m_stFrameData.nHeight;
    char* pSrcBuffer = MainWindow::instance()->GetImageSrcBuffer(imageNum);

    DxRaw8toRGB24(m_stFrameData.pImgBuf,
                  pSrcBuffer,
                  nWidth,
                  nHeight,
                  DX_BAYER_CONVERT_TYPE::RAW2RGB_ADAPTIVE,
                  DX_PIXEL_COLOR_FILTER::BAYERRG,
                  true);


    //writeBmpFile(pSrcBuffer,nWidth,nHeight,imageNum);

    // 加载BMP图像
    QImage image(nWidth,nHeight,QImage::Format_BGR888);
    memcpy(image.bits(),pSrcBuffer,nWidth * nHeight * 3);

    image.save("D:\\test\\seat\\korol1.bmp");
    return emStatus;
}

int Daheng5000Camera::SaveBmp(const char* pFilePath){
    m_pBitmap->SaveBmp(pFilePath);
    return 0;
}

int Daheng5000Camera::SaveJpeg(const char* pFilePath){
    m_pBitmap->SaveJPEG(pFilePath);
    return 0;
}
